﻿using UnityEngine;
using System.Collections;
using System.IO;
using System.Collections.Generic;

public class MapGenerator {

	private static MapGrid InstanceGrid(GameObject prefab, int row, int column)
	{
		if(null == prefab)
			return null;
		
		GameObject go = GameObject.Instantiate(prefab)as GameObject;
		go.transform.position = Map.MapLeftDownPos+ 
			new Vector3(column*MapGrid.GridWidth, row*MapGrid.GridHeight, 0);
		return go.GetComponent<MapGrid>();
	}
	public static Map GenerateMap(int row, int column)
	{
		int roadSize = 128;
		int[,] road = GenerateNoiseMap(roadSize);
		Map map = new Map(row, column);
		//load grid prefab
		GameObject nonePrefab = Resources.Load("Prefabs/Grids/grid_none")as GameObject;
		GameObject normalPrefab = Resources.Load("Prefabs/Grids/grid_normal")as GameObject;


		//copy road to map
		for(int i = 0; i<(int)(row*0.25f); i++)
		{
			for(int j=0; j<column; j++)
			{
				//
				int roadI = (int) (i*roadSize/(row*0.25f));
				int roadJ = (int) (j*roadSize/column);
				if(road[roadJ, roadI] == 1)
				{
					MapGrid mg = InstanceGrid(nonePrefab, i, j);
					map.SetMapGrid(mg, i, j);
				}
			}
		}
		//copy road to map
		int m=0;
		for(int i = (int)(row-row*0.25f); i<row; i++, m++)
		{
			for(int j=0; j<column; j++)
			{
				//
				int roadI = (int) (m*roadSize/(row*0.25f));
				int roadJ = (int) (j*roadSize/column);
				roadI = roadSize - 1 - roadI;
				if(road[roadJ, roadI] == 1)
				{
					map.SetMapGrid(InstanceGrid(nonePrefab, i, j), i, j);
				}
			}
		}
		//init map
		for(int i=0; i<row; i++)
		{
			for(int j=0; j<column; j++)
			{
				
				if(map.GetMapGrid(i, j) == null)
				{
					map.SetMapGrid(InstanceGrid(normalPrefab, i, j), i, j);
				}		
			}
		}
		//find a rand enter
		for(int i =0; i<column; i++)
		{
			if(map.GetMapGrid(0, i).Type == MapGrid.GridType.Normal)
			{
				map.StartIndex = new IntVector2(0, i);
			}
		}
		return map;
	}
	//return [0, 1]
	private static float Noise1D()
	{
		return Random.Range(0, 101)*0.01f;
	}
	/// <summary>
	/// 生成一条从左到右随机的折线
	/// </summary>
	/// <param name="row">Row.</param>
	/// <param name="column">Column.</param>
	private static int[,] GenerateNoiseMap(int size)
	{
		int seed = GameUtils.GetUTCTimeStamp();
		Random.seed = seed;

		List<Vector2> line = new List<Vector2>();
		Vector2 startUV = new Vector2( 0, Noise1D());
		Vector2 nextUV = startUV;
		float temp=0;
		int type = 0;

		line.Add(startUV);

		while(true)
		{
			if(nextUV.x >= 1)
			{
				break;
			}
				
			if(nextUV.y >= 1 || type == 0){
				if(type == 1)
					type = Random.Range(1, 3);
				else
					type = 1;
			}else if(nextUV.y <= 0 || type == 2){
				if(type == 1)
					type = Random.Range(0, 2);
				else
					type = 1;
			}else{
				type = Random.Range(0, 3);
			}
			switch(type)
			{
			//right
			case 1:
				temp = startUV.x + Noise1D()*0.1f + 0.025f;
				temp = temp > 1 ? 1:temp;
				temp = temp < 0 ? 0:temp;
				nextUV = new Vector2(temp, startUV.y);
				startUV = nextUV;
				line.Add(nextUV);
				break;
			//up
			case 0:
				temp = startUV.y + Noise1D()*0.2f + 0.1f;
				temp = temp > 1 ? 1:temp;
				temp = temp < 0 ? 0:temp;
				nextUV = new Vector2(startUV.x, temp);
				startUV = nextUV;
				line.Add(nextUV);
				break;
			//down
			case 2:
				temp = startUV.y - Noise1D()*0.2f + 0.1f;
				temp = temp > 1 ? 1:temp;
				temp = temp < 0 ? 0:temp;
				nextUV = new Vector2(startUV.x, temp);
				startUV = nextUV;
				line.Add(nextUV);
				break;
			}
		}
		//
		int[,] road = new int[size, size];
		IntVector2 p0 = null, p1 = null;
		foreach(Vector2 p in line)
		{
			if(null == p0)
			{
				p0 = new IntVector2((int)( p.x*(size-1) ), (int)( p.y*(size-1) ));
				continue;
			}
			p1 = new IntVector2((int)( p.x*(size-1) ), (int)( p.y*(size-1) ));

			//default dir:down
			IntVector2 dir = new IntVector2(0, -1);
			//right
			if((p1-p0).x > 0)
			{
				dir = new IntVector2(1, 0);
			}else if((p1-p0).y > 0)//up
			{
				dir = new IntVector2(0, 1);
			}

			road[p0.x, p0.y] = 1;
			FillRoad(ref road, p0);
			while(p0 != p1)
			{
				p0 += dir;
				road[p0.x, p0.y] = 1;
				//
				FillRoad(ref road, p0);
			}
		}
		//
		#region draw the road to a png tex.
		#if UNITY_EDITOR
		Color[] roadColor = new Color[size*size];
		for(int i=0; i<size; i++)
		{
			for(int j=0; j<size; j++)
			{
				roadColor[i+j*size] = new Color( road[i, j], 0, 0);
			}
		}
		Texture2D tex = new Texture2D(size, size);
		tex.SetPixels(roadColor);
		tex.Apply();
		GameUtils.SaveTextureAsPNG(tex, Application.dataPath+"/Textures/road.png");
		#endif
		#endregion

		return road;
	}
	private static void FillRoad(ref int[,] road, IntVector2 p)
	{
		int fill = p.y;
		while(fill != 0)
		{
			fill -= 1;
			road[p.x, fill] = 1;
		}
	}
}
